package be.ac.info.fundp.TVLParser.SyntaxTree;

import be.ac.info.fundp.TVLParser.Util.Util;
import be.ac.info.fundp.TVLParser.exceptions.AmbiguousReferenceException;
import be.ac.info.fundp.TVLParser.exceptions.BadTypeUseException;
import be.ac.info.fundp.TVLParser.exceptions.ChildrenFeatureNotFoundException;
import be.ac.info.fundp.TVLParser.exceptions.ExpressionOutOfBoundException;
import be.ac.info.fundp.TVLParser.exceptions.ExpressionTypeViolatingAttributeTypeException;
import be.ac.info.fundp.TVLParser.exceptions.IDEnumValuesConflictException;
import be.ac.info.fundp.TVLParser.exceptions.IllegalExpressionException;
import be.ac.info.fundp.TVLParser.exceptions.SetExpressionMemberOutOfBoundException;
import be.ac.info.fundp.TVLParser.exceptions.SetExpressionMemberViolatingAttributeTypeException;
import be.ac.info.fundp.TVLParser.exceptions.SharedFeatureUsingParentConstructorException;
import be.ac.info.fundp.TVLParser.exceptions.SharedFeatureUsingParentSelectorException;
import be.ac.info.fundp.TVLParser.exceptions.SymbolNotFoundException;

public class MinusExpression implements Expression {
	
	Expression expression1, expression2;
	
	public MinusExpression(Expression e1, Expression e2) {
		this.expression1 = Util.removeParentheses(e1);
		this.expression2 = Util.removeParentheses(e2);
	}
	
	public MinusExpression(Expression e1) {
		this.expression1 = Util.removeParentheses(e1);
		this.expression2 = null;
	}

	/**
	 * @return the expression1
	 */
	public Expression getExpression1() {
		return expression1;
	}
	

	/**
	 * @return the expression2
	 */
	public Expression getExpression2() {
		return expression2;
	}
	
	public int getType() throws IllegalExpressionException, SymbolNotFoundException, AmbiguousReferenceException, SharedFeatureUsingParentConstructorException, BadTypeUseException, SharedFeatureUsingParentSelectorException, ChildrenFeatureNotFoundException, IDEnumValuesConflictException, NumberFormatException, SetExpressionMemberOutOfBoundException, SetExpressionMemberViolatingAttributeTypeException, ExpressionTypeViolatingAttributeTypeException, ExpressionOutOfBoundException {
		if (this.expression2 == null) 
			return this.getTypeUMinus();
		else
			return this.getTypeMinus();
	}
	
	
	public int getTypeMinus() throws IllegalExpressionException, SymbolNotFoundException, AmbiguousReferenceException, SharedFeatureUsingParentConstructorException, BadTypeUseException, SharedFeatureUsingParentSelectorException, ChildrenFeatureNotFoundException, IDEnumValuesConflictException, NumberFormatException, SetExpressionMemberOutOfBoundException, SetExpressionMemberViolatingAttributeTypeException, ExpressionTypeViolatingAttributeTypeException, ExpressionOutOfBoundException {
		if (this.expression1.getType() == Expression.INT) {
			if (this.expression2.getType() == Expression.INT) {
				return Expression.INT;
			}
			else {
				if (this.getExpression2().getType() == Expression.REAL) {
					return Expression.REAL;
				}
				else {
					throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. The type of the right paramater ( "+this.expression2.toString()+" ) of a minus expression must be real or int. Currently,  its type is "+Util.toStringExpressionType(this.expression2.getType())+".");
				}
			}
		}
		else {
			if (this.expression1.getType() == Expression.REAL) {
				if (this.expression2.getType() == Expression.INT) {
					return Expression.REAL;
				}
				else {
					if (this.getExpression2().getType() == Expression.REAL) {
						return Expression.REAL;
					}
					else {
						throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. The type of the right paramater ( "+this.expression2.toString()+" ) of a minus expression must be real or int. Currently,  its type is "+Util.toStringExpressionType(this.expression2.getType())+".");
					}
				}
			}
			else {
				throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. The type of the left paramater ( "+this.expression1.toString()+" ) of a minus expression must be real or int. Currently,  its type is "+Util.toStringExpressionType(this.expression1.getType())+".");
			}
		}
	}
	
	
	public int getTypeUMinus() throws IllegalExpressionException, SymbolNotFoundException, AmbiguousReferenceException, SharedFeatureUsingParentConstructorException, BadTypeUseException, SharedFeatureUsingParentSelectorException, ChildrenFeatureNotFoundException, IDEnumValuesConflictException, NumberFormatException, SetExpressionMemberOutOfBoundException, SetExpressionMemberViolatingAttributeTypeException, ExpressionTypeViolatingAttributeTypeException, ExpressionOutOfBoundException {
		if (this.expression1.getType() == Expression.REAL)
			return Expression.REAL;
		if (this.expression1.getType() == Expression.INT)
			return Expression.INT;
		throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. The type of the paramater ( "+this.expression1.toString()+" ) of an unary minus expression must be int or real. Currently,  its type is "+Util.toStringExpressionType(this.expression1.getType())+".");
		// Si l'on arrive ici, c'est qu'il y a eu un problème de type
	}

	
	public String toString() {
		if (this.expression2 == null) 
			return "- "+this.expression1.toString();
		else
			return this.expression1.toString()+" - "+this.expression2.toString();
	}
	
	public Expression toNormalForm() {
		if (this.expression2 == null)
			return new MinusExpression(this.expression1.toNormalForm());
		else
			return new MinusExpression(this.expression1.toNormalForm(), this.expression2.toNormalForm());
	}

}
